package com.gongyinlian.personalprofilewebsiteserver.interceptor;

import com.gongyinlian.personalprofilewebsiteserver.common.enums.ResultCode;
import com.gongyinlian.personalprofilewebsiteserver.common.exception.BusinessException;
import com.gongyinlian.personalprofilewebsiteserver.utils.JwtUtil;
import com.gongyinlian.personalprofilewebsiteserver.utils.UserHolder;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * JWT拦截器
 * 用于验证Token并提取用户信息
 * 
 * @author personal-profile-website
 * @date 2024-10-27
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class JwtInterceptor implements HandlerInterceptor {
    
    private final JwtUtil jwtUtil;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 1. 获取请求路径（用于日志）
        String requestUri = request.getRequestURI();
        
        // 2. 从请求头中获取Token
        String token = jwtUtil.getTokenFromRequest(request);
        
        // 3. Token为空，抛出异常
        if (token == null || token.trim().isEmpty()) {
            log.warn("访问受保护资源失败：Token为空 - URI: {}", requestUri);
            throw new BusinessException(ResultCode.TOKEN_MISSING);
        }
        
        // 4. 验证Token是否有效
        if (!jwtUtil.validateToken(token)) {
            log.warn("访问受保护资源失败：Token无效 - URI: {}", requestUri);
            throw new BusinessException(ResultCode.TOKEN_INVALID);
        }
        
        // 5. 检查Token是否过期
        if (jwtUtil.isTokenExpired(token)) {
            log.warn("访问受保护资源失败：Token已过期 - URI: {}", requestUri);
            throw new BusinessException(ResultCode.TOKEN_EXPIRED);
        }
        
        // 6. 从Token中提取用户信息
        Long userId = jwtUtil.getUserIdFromToken(token);
        String username = jwtUtil.getUsernameFromToken(token);
        
        if (userId == null || username == null) {
            log.warn("访问受保护资源失败：无法从Token中提取用户信息 - URI: {}", requestUri);
            throw new BusinessException(ResultCode.TOKEN_INVALID);
        }
        
        // 7. 将用户信息存入ThreadLocal
        UserHolder.setUser(userId, username);
        
        log.debug("Token验证成功 - 用户: {}, ID: {}, URI: {}", username, userId, requestUri);
        
        return true;
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 请求完成后清除ThreadLocal，防止内存泄漏
        UserHolder.clear();
    }
}

